﻿#include "mapmanager.h"
#include "basemap.h"
#include "baserole.h"
#include "common/common.h"
#include "monsterrole.h"

#include <QtAlgorithms>
#include <QJsonDocument>
#include <QDomDocument>
#include <QSettings>
#include <QFile>

initialiseSingleton(MapManager);

MapManager::MapManager(QObject *parent)
    : CWebSocketServer(parent),
      mListenPort(0),
      nHttpServerPort(80)
{
    setAutoDeleteSocket(false);

    mHttpServer.setNetworkFrameManager(this);
    mHttpServer.setCurrentWorkingPath(QCoreApplication::applicationDirPath()+
                                          "/resources/html");

    init_dbpool(false,this);
    m_SqliteDataProvider.connect(QCoreApplication::applicationDirPath()+
                                         QString::fromLocal8Bit("/resources/gh_data.db"));

    connect(this, SIGNAL(signalsConnectedNetMes(QWebSocket*)),
            this, SLOT(slots_signalsConnectedNetMes(QWebSocket*)));
    connect(this, SIGNAL(signalsDisconnectedNetMes(QWebSocket*)),
            this, SLOT(slots_signalsDisconnectedNetMes(QWebSocket*)),
            Qt::QueuedConnection);
    connect(this, SIGNAL(signalsNetText(QWebSocket*,QString)),
            this, SLOT(slots_signalsNetText(QWebSocket*,QString)));

    connect(&mUpdateTimer, SIGNAL(timeout()), this, SLOT(update()));
    mUpdateTimer.start(10);
}

MapManager::~MapManager()
{
    deleteMapList();
    clearAllBulletInfos();

    clean_dbpool();
}

/**
 * @brief MapManager::startServer 启动服务器
 */
void MapManager::startServer(void)
{
    if(mListenPort <= 0) return;

    this->OpenServer(mListenPort);

    // 启动http服务器
    if(!mHttpServer.isRunning() &&
        mHttpServer.listen(nHttpServerPort))
    {
        print_log(LOG_INFO,
                  QString::fromLocal8Bit("http服务器启动成功,IP:")+
                  this->getHttpServerIP()+
                  QString::fromLocal8Bit(" 端口:")+
                  QString::asprintf("%d",nHttpServerPort),
                  "1|0|1");
    }
}

/**
 * @brief MapManager::loadSystemConfigFromINI 从ini中导入系统配置
 * @param filepath
 */
void MapManager::loadSystemConfigFromINI(QString filepath)
{
    if(filepath == "") return;

    QSettings pconfigIni(filepath, QSettings::IniFormat);
    pconfigIni.setIniCodec("utf-8");

    pconfigIni.beginGroup("httpServer");
    setHttpServerIP(pconfigIni.value("serverip").toString());
    setHttpServerPort(pconfigIni.value("serverport").toInt());
    pconfigIni.endGroup();

    pconfigIni.beginGroup("system");
    setProName(pconfigIni.value("proname").toString());
    setViewSize(convertStringToSize(pconfigIni.value("viewSize").toString(),"|"));
    pconfigIni.endGroup();
}

/**
 * @brief MapManager::loadMonsterFromXML 从XML中导入怪物配置
 * @param filepath
 * @return
 */
bool MapManager::loadMonsterFromXML(QString filepath)
{
    return mRoleManager.loadMonsterFromXML(filepath);
}

/**
 * @brief MapManager::loadGradeFromXML 从XML中导入用户等级信息
 * @param filepath
 * @return
 */
bool MapManager::loadGradeFromXML(QString filepath)
{
    if(filepath == "") return false;

    QDomDocument doc;
    QFile file(filepath);
    if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
        return false;
    }

    if (!doc.setContent(&file)) {
        file.close();
        return false;
    }

    QDomElement root = doc.documentElement();
    QDomNode n = root.firstChild();
    while (!n.isNull())
    {
        if (n.isElement()) {
            QDomElement e = n.toElement();
            if (e.tagName() == "gradeinfo")
            {
                int id = e.attribute("id").toInt();
                QString name = e.attribute("name");
                int experience = e.attribute("experience").toInt();

                mGradeInfoList[experience] = tagGradeInfo(id,
                                                    name,
                                                    experience);

                print_log(LOG_INFO,
                          QString::fromLocal8Bit("导入等级信息:")+
                                   name+
                                   QString::fromLocal8Bit(" ID:")+
                                   QString::asprintf("%d",id)+
                                   QString::fromLocal8Bit(" 名称:")+
                                   name+
                                   QString::fromLocal8Bit(" 经验值:")+
                                   QString::asprintf("%d",experience),
                          "1|0|1");
            }
        }

        n = n.nextSibling();
    }

    file.close();

    return true;
}

/**
 * @brief MapManager::loadBulletFromXML 从XML中导入弹药信息
 * @param filepath
 * @return
 */
bool MapManager::loadBulletFromXML(QString filepath)
{
    if(filepath == "") return false;

    QDomDocument doc;
    QFile file(filepath);
    if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
        return false;
    }

    if (!doc.setContent(&file)) {
        file.close();
        return false;
    }

    QDomElement root = doc.documentElement();
    QDomNode n = root.firstChild();
    while (!n.isNull())
    {
        if (n.isElement()) {
            QDomElement e = n.toElement();
            if (e.tagName() == "bulletinfo")
            {
                int id = e.attribute("id").toInt();
                AmmunitionType type = (AmmunitionType)e.attribute("type").toInt();
                QString name = e.attribute("name");
                int speed = e.attribute("speed").toInt();
                int distance = e.attribute("distance").toInt();
                int harm = e.attribute("harm").toInt();
                int minsize = 0;
                int maxsize = 0;
                int bulletsize = 0;
                int bulletlenght = 0;
                int anglestep = 0;
                QString usbullet;
                int routecount = 0;

                switch(type)
                {
                case AMMUNITIONTYPE_ARMORPIERCING:         // 破甲弹
                {
                    minsize = e.attribute("minsize").toInt();
                    maxsize = e.attribute("maxsize").toInt();
                }
                    break;
                case AMMNUITIONTYPE_STRAIGHTSNAKE:         // 一字长蛇弹
                case AMMUUITIONTYPE_BLOOMING:              // 开花弹
                {
                    bulletsize = e.attribute("bulletsize").toInt();
                    bulletlenght = e.attribute("bulletlenght").toInt();
                }
                    break;
                case AMMUNITIONTYPE_WOMENSCATTERINGFLOWER:                // 天女散花弹
                {
                    minsize = e.attribute("minsize").toInt();
                    maxsize = e.attribute("maxsize").toInt();
                    anglestep = e.attribute("anglestep").toInt();
                }
                    break;
                case AMMNUITIONTYPE_MULTIROUTE:              // 多路弹
                {
                    usbullet = e.attribute("usbullet");
                    routecount = e.attribute("routecount").toInt();
                    bulletsize = e.attribute("bulletsize").toInt();
                    bulletlenght = e.attribute("bulletlenght").toInt();
                    anglestep = e.attribute("anglestep").toInt();
                }
                    break;
                default:
                    break;
                }

                mBulletInfoList[id] = new tagBulletInfo(id,
                                                        type,
                                                        name,
                                                        speed,
                                                        distance,
                                                        harm,
                                                        minsize,
                                                        maxsize,
                                                        bulletsize,
                                                        bulletlenght,
                                                        anglestep,
                                                        usbullet,
                                                        routecount);

                print_log(LOG_INFO,
                          QString::fromLocal8Bit("导入弹药:")+
                                   name+
                                   QString::fromLocal8Bit(" ID:")+
                                   QString::asprintf("%d",id)+
                                   QString::fromLocal8Bit(" 攻击速度:")+
                                   QString::asprintf("%d",speed)+
                                   QString::fromLocal8Bit(" 攻击距离:")+
                                   QString::asprintf("%d",distance)+
                                   QString::fromLocal8Bit(" 攻击伤害:")+
                                   QString::asprintf("%d",harm),
                          "1|0|1");
            }
        }

        n = n.nextSibling();
    }

    file.close();

    return true;
}

/**
 * @brief MapManager::loadMapFromXML 从XML中导入地图信息
 * @param filepath
 */
bool MapManager::loadMapFromXML(QString filepath)
{
    if(filepath == "") return false;

    QDomDocument doc;
    QFile file(filepath);
    if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
        return false;
    }

    if (!doc.setContent(&file)) {
        file.close();
        return false;
    }

    QDomElement root = doc.documentElement();
    if (root.tagName() == "map")
    {
        mListenPort = root.attribute("listenport").toInt();

        print_log(LOG_INFO,
                           QString::fromLocal8Bit("地图侦听端口:")+
                           QString::asprintf("%d",mListenPort),
                  "1|0|1");
    }

    QDomNode n = root.firstChild();
    while (!n.isNull())
    {
        if (n.isElement()) {
            QDomElement e = n.toElement();

            if (e.tagName() == "mapinfo")
            {
                BaseMap *pBaseMap = new BaseMap(e.attribute("id").toInt());
                pBaseMap->setName(e.attribute("name"));
                pBaseMap->setRect(convertStringToRect(e.attribute("rect")));
                pBaseMap->setTileSize(convertStringToSize(e.attribute("tilesize")));
                pBaseMap->setMaxMonsterCount(e.attribute("maxmonster").toInt());
                pBaseMap->setPlayerStartPos(convertStringToPoint(e.attribute("startpos")));

                this->addMap(pBaseMap);

                print_log(LOG_INFO,
                          QString::fromLocal8Bit("导入地图:")+
                                   pBaseMap->getName()+
                                   QString::fromLocal8Bit(" ID:")+
                                   QString::asprintf("%d",pBaseMap->getMapIndex())+
                                   QString::fromLocal8Bit(" 地砖数量:")+
                                   QString::asprintf("%d,%d",pBaseMap->getTileSize().width(),pBaseMap->getTileSize().height())+
                                   QString::fromLocal8Bit(" 玩家初始位置:")+
                                   QString::asprintf("%d,%d",pBaseMap->getPlayerStartPos().x(),pBaseMap->getPlayerStartPos().y())+
                                   QString::fromLocal8Bit(" 最大怪物数量:")+
                                   QString::asprintf("%d",pBaseMap->getMaxMonsterCount())+
                                   QString::fromLocal8Bit(" 范围:")+
                                   QString::asprintf("%d,%d,%d,%d",pBaseMap->getRect().x(),pBaseMap->getRect().y(),pBaseMap->getRect().width(),pBaseMap->getRect().height()),
                          "1|0|1");

                QDomNode nn = e.firstChild();
                while (!nn.isNull())
                {
                    if (nn.isElement()) {
                        QDomElement ee = nn.toElement();

                        if (ee.tagName() == "mapentrance")
                        {
                            QRect rect = convertStringToRect(ee.attribute("rect"));
                            int targetmap = ee.attribute("targetmap").toInt();
                            QString remark = ee.attribute("remark");

                            pBaseMap->addMapEntrance(tagMapEntrance(rect,targetmap,remark));

                            print_log(LOG_INFO,
                                      QString::fromLocal8Bit("地图入口:")+
                                               QString::fromLocal8Bit(" 范围:")+
                                               QString::asprintf("%d,%d,%d,%d",rect.x(),rect.y(),rect.width(),rect.height())+
                                               QString::fromLocal8Bit(" 目标地图:")+
                                               QString::asprintf("%d",targetmap),
                                      "1|0|1");
                        }
                    }

                    nn = nn.nextSibling(); // 移动到下一个节点
                }


            }
        }

        n = n.nextSibling(); // 移动到下一个节点
    }

    file.close();

    return true;
}

/**
 * @brief MapManager::sendNotice 发送指定的公告给客户端
 * @param type
 * @param message
 */
void MapManager::sendNotice(BaseRole *role,QString type,QString message)
{
    if(type == "" || message == "" ||
       role == NULL || role->getRoleType() != ROLETYPE_PLAYER)
        return;

    QJsonObject contentObj;
    contentObj["type"] = type;
    contentObj["data"] = message;

    QJsonObject mesObj;
    mesObj["msgtype"] = IDD_NETWORK_NOTICE;
    mesObj["content"] = contentObj;

    this->Send(role->getWebSocket(),JsonToString(mesObj).toUtf8());
}

/**
 * @brief MapManager::clearAllBulletInfos 清除所有的弹药信息
 */
void MapManager::clearAllBulletInfos(void)
{
    QHash<int,tagBulletInfo*>::iterator iter = mBulletInfoList.begin();
    for(;iter != mBulletInfoList.end();++iter)
        delete iter.value();

    mBulletInfoList.clear();
}

/**
 * @brief MapManager::getBulletInfo 得到指定ID的弹药信息
 * @param id
 * @return
 */
tagBulletInfo* MapManager::getBulletInfo(int id)
{
    QHash<int,tagBulletInfo*>::iterator iter = mBulletInfoList.find(id);
    if(iter != mBulletInfoList.end())
        return iter.value();

    return NULL;
}

/**
 * @brief MapManager::getMapById 得到指定ID的地图
 * @param id
 * @return
 */
BaseMap* MapManager::getMapById(int id)
{
    QHash<int,BaseMap*>::iterator iter = mBaseMapList.find(id);
    if(iter != mBaseMapList.end())
        return iter.value();

    return NULL;
}

/**
 * @brief MapManager::addMap 添加一个地图到管理器中
 * @param map
 * @return
 */
bool MapManager::addMap(BaseMap *map)
{
    if(map == NULL || isExistMap(map)) return false;

    mBaseMapList[map->getMapIndex()] = map;

    return true;
}

/**
 * @brief MapManager::isExistMap 检测指定地图是否存在
 * @param map
 * @return
 */
bool MapManager::isExistMap(BaseMap *map)
{
    if(map == NULL) return false;

    QHash<int,BaseMap*>::iterator iter = mBaseMapList.find(map->getMapIndex());
    if(iter == mBaseMapList.end())
        return false;

    return true;
}

/**
 * @brief MapManager::deleteMapList 清除所有的地图
 */
void MapManager::deleteMapList(void)
{
    QHash<int,BaseMap*>::iterator iter = mBaseMapList.begin();
    for(;iter != mBaseMapList.end();iter++)
    {
        delete iter.value();
    }

    mBaseMapList.clear();
}

/**
 * @brief MapManager::onHttpOneAccepted 处理http请求
 * @param session
 */
bool MapManager::OnProcessHttpAccepted(QObject *obj,const QPointer< JQHttpServer::Session > &session)
{
    QString prequestUrl = session->requestUrl();

    bool isProcessed = false;

    if(obj == &mHttpServer)
    {
        if(prequestUrl == "/")         // 打开初始页面
        {
            QString pContent = QString(mHttpServer.getResourceManager()->getFile(QCoreApplication::applicationDirPath()+"/resources/html/index.html"));
            pContent = pContent.arg(getHttpServerIP() != "" ? getHttpServerIP() : getLocalIP().toString(),
                                    QString::asprintf("%d",getListenPort()),
                                    QString::asprintf("%d",getViewSize().width()),
                                    QString::asprintf("%d",getViewSize().height()),
                                    getProName());

            session->replyBytes(pContent.toUtf8(),"text/html; charset=UTF-8");
        }
        else if(prequestUrl == "/login")         // 打开登录页面
        {
            QString pContent = QString(mHttpServer.getResourceManager()->getFile(QCoreApplication::applicationDirPath()+"/resources/html/login.html"));
            pContent = pContent.arg(getProName());

            session->replyBytes(pContent.toUtf8(),"text/html; charset=UTF-8");
        }
        else if(prequestUrl == "/getuserdata")     // 得到用户信息
        {
            QMap< QString, QString > content;
            QString content2 = QString(session->requestBody());
            QStringList tmpStringList = content2.split("&");
            if(!tmpStringList.isEmpty())
            {
                for(int i=0;i<tmpStringList.size();i++)
                {
                    QStringList tmpStringList2 = tmpStringList[i].split("=");
                    if(tmpStringList2.size() == 2)
                        content[tmpStringList2[0]] = tmpStringList2[1];
                }
            }

            QString username = QByteArray::fromPercentEncoding(content["username"].toUtf8());
            QString userpwd = content["userpwd"];

            if(!username.isEmpty() && !userpwd.isEmpty())
            {
                tagDBUserData pDBUserData;
                if(m_SqliteDataProvider.getUserData(username,userpwd,
                                 &pDBUserData,
                                 "HttpAccepted_conn"+
                                 QString::asprintf("%d",getpid()),
                                 false))
                {
                    // 更新用户IP
                    pDBUserData.lastip = session->requestSourceIp();

                    m_SqliteDataProvider.updateUserData(&pDBUserData,
                                                             "HttpAccepted_conn"+
                                                             QString::asprintf("%d",getpid()),
                                                             false);

                    QJsonObject mesObj;
                    mesObj["msgtype"] = IDD_NETWORK_PLAYERINFO;
                    mesObj["id"] = pDBUserData.id;
                    mesObj["username"] = pDBUserData.username;
                    mesObj["password"] = pDBUserData.password;
                    mesObj["type"] = pDBUserData.type;

                    session->replyBytes(JsonToString(mesObj).toUtf8(),"text/html; charset=UTF-8");
                }
                else
                {
                    QJsonObject mesObj;
                    mesObj["msgtype"] = IDD_NETWORK_MSG_ERROR;
                    mesObj["type"] = IDD_NETWORK_MSG_LOGIN_FAIL;

                    session->replyBytes(JsonToString(mesObj).toUtf8(),"text/html; charset=UTF-8");
                }
            }
            else
            {
                session->replyBytes(QString::fromLocal8Bit("当前页面不存在！").toUtf8(),"text/html; charset=UTF-8");
            }
        }

        isProcessed = true;
    }

    return isProcessed ? isProcessed : NetworkFrameManager::OnProcessHttpAccepted(obj,session);
}

/**
 * @brief MapManager::slots_signalsNetText 处理网络字符串消息
 * @param conn
 * @param mes
 */
void MapManager::slots_signalsNetText(QWebSocket *conn,QString mes)
{
    QJsonObject mesObj = StringToJson(mes);

    switch(mesObj["msgtype"].toInt())
    {
    case IDD_NETWORK_PLAYERCHANGE:          // 玩家操作改变
    {
        int distance = mesObj["distance"].toInt();
        double angle = mesObj["angle"].toDouble();

        BaseRole *pPlayer = mRoleManager.getRoleByWebsocket(conn);
        if(pPlayer)
        {
            QPoint tmppoint = calculateNewPoint(pPlayer->getPosition(),distance,angle);

            pPlayer->setAngle(angle);
            pPlayer->setPosition(tmppoint);

            if(pPlayer->isAngleChanged() || pPlayer->isPosChanged())
                pPlayer->setStateChanged(true);

            MapManager::getSingleton().updateRoleMap(pPlayer);
        }
    }
        break;
    case IDD_NETWORK_ENTERMAP:             // 玩家进入地图
    {
        int userid = mesObj["userid"].toInt();
        int targetmap = mesObj["targetmap"].toInt();

        BaseRole *pRole = mRoleManager.getRoleById(userid);
        BaseMap *pMap = getMapById(targetmap);
        if(pRole == NULL ||
           pMap == NULL ||
           pRole->getRoleType() != ROLETYPE_PLAYER)
        {
            QJsonObject mesObj;
            mesObj["msgtype"] = IDD_NETWORK_MSG_ERROR;
            mesObj["type"] = IDD_NETWORK_MSG_ENTERMAP_FAIL;

            this->Send(conn,JsonToString(mesObj).toUtf8());
            return;
        }

        // 从地图中清除角色
        deleteRoleFromMap(pRole);

        // 从关联NPC列表中清除
        mRoleManager.delRoleFromMonsterList(pRole);

        // 从在线角色可视列表中清除
        mRoleManager.delRoleFromViewList(pRole);

        // 给当前玩家发送在线玩家列表
        QJsonObject returnObj;
        returnObj["msgtype"] = IDD_NETWORK_DELETEROLE;
        returnObj["id"] = pRole->getID();

        this->SendAll(JsonToString(returnObj));

        BaseMap *psrcMap = getMapById(pRole->getMapIndex());

        // 改变玩家当前地图
        pRole->setMapIndex(targetmap);

        // 重置玩家在地图中的位置
        pRole->setPosition(getMapById(pRole->getMapIndex())->getPlayerStartPos());

        // 发送所有的角色到客户端
        sendAddRoleMsg(pRole);

        // 发送所有弹药信息
        sendBulletInfoMsg(pRole);

        // 地图中加入该玩家
        mBaseMapList[pRole->getMapIndex()]->addRoleToMap(pRole);

        print_log(LOG_INFO,
                  QString::fromLocal8Bit("玩家'")+
                  pRole->getName()+
                  QString::fromLocal8Bit("' 从地图 ‘")+
                  psrcMap->getName()+
                  QString::fromLocal8Bit("’ 跳转到地图 ‘")+
                  pMap->getName()+
                  QString::fromLocal8Bit("’."),
                  "1|0|1");
    }
        break;
    case IDD_NETWORK_ENTERSERVER:          // 玩家进入服务器
    {
        int userid = mesObj["userid"].toString().toInt();
        QString password = mesObj["password"].toString();

        tagDBUserData pDBUserData;
        if(m_SqliteDataProvider.getUserDataById(userid,password,
                         &pDBUserData,
                         "HttpAccepted_conn"+
                         QString::asprintf("%d",getpid()),
                         false))
        {
            BaseRole *pBaseRole = new BaseRole();
            pBaseRole->setWebSocket(conn);
            pBaseRole->setName(pDBUserData.username);
            pBaseRole->setPosition(!pDBUserData.curmappos.isNull() ? pDBUserData.curmappos :
                                                                 getMapById(pDBUserData.curmap)->getPlayerStartPos());
            pBaseRole->setAngle(0.0f);
            pBaseRole->setViewRect(QRect(QPoint(0,0),getViewSize()));
            pBaseRole->setMapIndex(pDBUserData.curmap <= 0 ? 1 : pDBUserData.curmap);
            pBaseRole->setID(pDBUserData.id);
            pBaseRole->setBlood(pDBUserData.blood);
            pBaseRole->setDefense(pDBUserData.defense);
            pBaseRole->setShape(pDBUserData.shapeinfo);
            pBaseRole->setExperience(pDBUserData.experience);
            pBaseRole->setGrade(pDBUserData.grade);
            pBaseRole->setUsingBullet(pDBUserData.currentusingbullet);

            QJsonArray bulletArr = StringToJsonArray(pDBUserData.bulletquantity);
            for(int i=0;i<bulletArr.size();i++)
            {
                QJsonObject bulletObj = bulletArr[i].toObject();
                pBaseRole->setBulletQuantity(bulletObj["id"].toInt(),bulletObj["quantity"].toInt());
            }

            mRoleManager.addPlayer(pBaseRole);

            // 发送所有的角色到客户端
            sendAddRoleMsg(pBaseRole);

            // 发送所有弹药信息
            sendBulletInfoMsg(pBaseRole);

            // 地图中加入该玩家
            mBaseMapList[pBaseRole->getMapIndex()]->addRoleToMap(pBaseRole);

            // 发送欢迎公告
            sendNotice(pBaseRole,"info",QString::fromLocal8Bit("欢迎来到'灵魂战机online',祝您游戏愉快!"));

            print_log(LOG_INFO,
                      QString::fromLocal8Bit("加入玩家:")+
                               pBaseRole->getName()+
                               QString::asprintf(" ID:%d",pBaseRole->getID())+
                               QString::fromLocal8Bit(" 坐标:")+
                               QString::asprintf("%d,%d",pBaseRole->getPosition().x(),pBaseRole->getPosition().y())+
                               QString::fromLocal8Bit(" 角度:")+
                               QString::asprintf("%f",pBaseRole->getAngle()),
                      "1|0|1");
        }
        else
        {
            QJsonObject mesObj;
            mesObj["msgtype"] = IDD_NETWORK_MSG_ERROR;
            mesObj["type"] = IDD_NETWORK_MSG_ENTERSERVER_FAIL;

            this->Send(conn,JsonToString(mesObj).toUtf8());
        }
    }
        break;
    case IDD_NETWORK_REINCARNATION:        // 角色重生
    {
        int userid = mesObj["userid"].toInt();

        BaseRole *pBaseRole = mRoleManager.getRoleById(userid);
        if(pBaseRole == NULL ||
           pBaseRole->getRoleType() != ROLETYPE_PLAYER ||
           pBaseRole->getState() != ROLESTATE_DEATH)
        {
            QJsonObject mesObj;
            mesObj["msgtype"] = IDD_NETWORK_MSG_ERROR;
            mesObj["type"] = IDD_NETWORK_REINCARNATION_FAIL;

            this->Send(conn,JsonToString(mesObj).toUtf8());

            return;
        }

        pBaseRole->setBlood(100);
        pBaseRole->setState(ROLESTATE_WAITING);
        pBaseRole->setPosition(mBaseMapList[pBaseRole->getMapIndex()]->generatearandombirthcoordinate());

        // 发送所有的角色到客户端
        sendAddRoleMsg(pBaseRole);

        // 地图中加入该玩家
        mBaseMapList[pBaseRole->getMapIndex()]->addRoleToMap(pBaseRole);
    }
        break;
    case IDD_NETWORK_ATTACK:                 // 攻击操作
    {
        BaseRole *pPlayer = mRoleManager.getRoleByWebsocket(conn);
        if(pPlayer)
        {
            this->sendViewRoles(pPlayer,mes);
        }
    }
        break;
    case IDD_NETWORK_ATTACKED:               // 被攻击操作
    {
        int attackid = mesObj["attackid"].toInt();
        int beattackid = mesObj["beattackid"].toInt();
        int bulletid = mesObj["bulletid"].toInt();

        // 找到被攻击的角色
        BaseRole *pattackBaseRole = mRoleManager.getRoleById(attackid);
        BaseRole *pbeattackBaseRole = mRoleManager.getRoleById(beattackid);
        tagBulletInfo *pBulletInfo = NULL;

        // 找到攻击的子弹
        QHash<int,tagBulletInfo*>::iterator iter = mBulletInfoList.find(bulletid);
        if(iter != mBulletInfoList.end())
            pBulletInfo = iter.value();

        if(pattackBaseRole == NULL || pBulletInfo == NULL || pbeattackBaseRole == NULL)
        {
            QJsonObject mesObj;
            mesObj["msgtype"] = IDD_NETWORK_MSG_ERROR;
            mesObj["type"] = IDD_NETWORK_ATTACK_FAIL;

            this->Send(conn,JsonToString(mesObj).toUtf8());
            return;
        }

        int damagevalue = pBulletInfo->harm - (pbeattackBaseRole->getDefense() / 100.0f);

        if(damagevalue <= 0)
        {
            QJsonObject mesObj;
            mesObj["msgtype"] = IDD_NETWORK_MSG_ERROR;
            mesObj["type"] = IDD_NETWORK_ATTACK_FAIL;

            this->Send(conn,JsonToString(mesObj).toUtf8());
            return;
        }

        if(pbeattackBaseRole->getBlood() > 0)
        {
            pbeattackBaseRole->setBlood(pbeattackBaseRole->getBlood()-damagevalue);

            // 更新玩家游戏信息
            m_SqliteDataProvider.updateUserGameData(pbeattackBaseRole,
                                                    "HttpAccepted_conn"+
                                                    QString::asprintf("%d",getpid()),
                                                    false);

            updateRoleGameInfo(pbeattackBaseRole);
        }

        // 如果被攻击角色死掉，攻击者经验加1
        if(pbeattackBaseRole->getBlood() <= 0)
        {
            pbeattackBaseRole->setState(ROLESTATE_DEATH);
            pattackBaseRole->setExperience(pattackBaseRole->getExperience()+1);

            tagGradeInfo *pGradeInfo = this->getGradeInfoByExperience(pattackBaseRole->getExperience());

            // 检测角色是否升级
            if(pGradeInfo && pGradeInfo->id > pattackBaseRole->getGrade())
            {
                pattackBaseRole->setGrade(pGradeInfo->id);
                pattackBaseRole->setExperience(0);
            }

            // 更新玩家游戏信息
            m_SqliteDataProvider.updateUserGameData(pattackBaseRole,
                                                    "HttpAccepted_conn"+
                                                    QString::asprintf("%d",getpid()),
                                                    false);

            updateRoleGameInfo(pattackBaseRole);

            // 从角色地图中清除这个角色
            deleteRoleFromMap(pbeattackBaseRole);

            // 如果攻击者是怪物的话，停止攻击，重新设置为等待状态
            if(pattackBaseRole->getRoleType() == ROLETYPE_MONSTER)
            {
                MonsterRole *pMonsterRole = static_cast<MonsterRole*>(pattackBaseRole);
                if(pMonsterRole)
                {
                    pMonsterRole->setState(ROLESTATE_WAITING);
                    pMonsterRole->setGuardPlayer(NULL);
                }
            }

            // 如果是怪物的话，重新放进空闲列表中
            if(pbeattackBaseRole->getRoleType() == ROLETYPE_MONSTER)
            {
                mRoleManager.returnTheMonsters(pbeattackBaseRole);
            }

            // 角色死掉，删除这个角色
            QJsonObject returnObj;
            returnObj["msgtype"] = IDD_NETWORK_DELETEROLE;
            returnObj["id"] = pbeattackBaseRole->getID();

            this->SendAll(JsonToString(returnObj));
        }
    }
        break;
    default:
        break;
    }
}

/**
 * @brief MapManager::sendViewRoles 发送消息给当前角色可见的所有其它角色
 * @param role
 * @param msg
 */
void MapManager::sendViewRoles(BaseRole * role,QString msg)
{
    if(role == NULL || msg == "")
        return;

    QList<BaseRole*> pbaserolelist = role->getViewRoleList();
    QList<BaseRole*>::iterator iter = pbaserolelist.begin();
    for(;iter != pbaserolelist.end();++iter)
    {
        if((*iter)->getRoleType() != ROLETYPE_PLAYER || (*iter)->getWebSocket() == NULL)
            continue;

        this->Send((*iter)->getWebSocket(),msg);
    }
}

/**
 * @brief MapManager::slots_signalsConnectedNetMes 处理一个新的连接到达
 * @param conn
 */
void MapManager::slots_signalsConnectedNetMes(QWebSocket *conn)
{

}

/**
 * @brief MapManager::deleteRoleFromMap 删除指定的角色
 * @param role
 */
void MapManager::deleteRoleFromMap(BaseRole *role)
{
    if(role == NULL) return;

    mBaseMapList[role->getMapIndex()]->delRoleFromMap(role);
}

/**
 * @brief MapManager::getGradeInfoByExperience 得到指定经验值的等级信息
 * @param experience
 * @return
 */
tagGradeInfo* MapManager::getGradeInfoByExperience(int experience)
{
    if(mGradeInfoList.isEmpty())
        return NULL;

    auto iter = mGradeInfoList.constEnd();
    while (iter != mGradeInfoList.constBegin()) {
        if(experience >= iter.key())
            return (tagGradeInfo*)(&(iter.value()));

        --iter; // 继续向前移动
    }

    return NULL;
}

/**
 * @brief MapManager::slots_signalsDisconnectedNetMes 处理一个连接关闭
 * @param conn
 */
void MapManager::slots_signalsDisconnectedNetMes(QWebSocket *conn)
{
    BaseRole *pplayer = mRoleManager.getRoleByWebsocket(conn);
    if(pplayer)
    {
        // 更新玩家地图信息
        m_SqliteDataProvider.updateUserMapData(pplayer,
                                                "HttpAccepted_conn"+
                                                QString::asprintf("%d",getpid()),
                                                false);

        // 从地图中清除角色
        deleteRoleFromMap(pplayer);

        // 从关联NPC列表中清除
        mRoleManager.delRoleFromMonsterList(pplayer);

        // 从在线角色可视列表中清除
        mRoleManager.delRoleFromViewList(pplayer);

        // 给当前玩家发送在线玩家列表
        QJsonObject returnObj;
        returnObj["msgtype"] = IDD_NETWORK_DELETEROLE;
        returnObj["id"] = pplayer->getID();

        this->SendAll(JsonToString(returnObj));
    }

    mRoleManager.deletePlayerByWebsocket(conn);

    if(!isAutoDeleteSocket())
    {
        // 手动清除这个socket
        conn->deleteLater();
    }
}

/**
 * @brief MapManager::updateRoleMap 更新角色地图信息
 * @param role
 */
void MapManager::updateRoleMap(BaseRole *role)
{
    if(role == NULL) return;

    mBaseMapList[role->getMapIndex()]->updateRoleMapTile(role);
}

/**
 * @brief MapManager::sendBulletInfoMsg 发送弹药信息
 */
void MapManager::sendBulletInfoMsg(BaseRole *role)
{
    QJsonArray bulletArray;

    QHash<int,tagBulletInfo*>::iterator iter = mBulletInfoList.begin();
    for(;iter != mBulletInfoList.end();++iter)
    {
        QJsonObject bulletObj;
        bulletObj["id"] = iter.value()->id;
        bulletObj["type"] = iter.value()->type;
        bulletObj["name"] = iter.value()->name;
        bulletObj["speed"] = iter.value()->speed;
        bulletObj["distance"] = iter.value()->distance;
        bulletObj["harm"] = iter.value()->harm;
        bulletObj["minsize"] = iter.value()->minsize;
        bulletObj["maxsize"] = iter.value()->maxsize;
        bulletObj["bulletsize"] = iter.value()->bulletsize;
        bulletObj["bulletlenght"] = iter.value()->bulletlenght;
        bulletObj["anglestep"] = iter.value()->anglestep;
        bulletObj["usbullet"] = iter.value()->usbullet;
        bulletObj["routecount"] = iter.value()->routecount;

        bulletArray.push_back(bulletObj);
    }

    // 给玩家发送弹药信息
    QJsonObject returnObj;
    returnObj["msgtype"] = IDD_NETWORK_BULLETINFO;
    returnObj["content"] = bulletArray;

    this->Send(role->getWebSocket(),
               JsonToString(returnObj));
}

/**
 * @brief MapManager::sendAddRoleMsg 发送添加角色消息
 * @param role
 */
void MapManager::sendAddRoleMsg(BaseRole *role)
{
    // 给当前玩家发送在线玩家列表
    QJsonObject returnObj;
    returnObj["msgtype"] = IDD_NETWORK_ADDROLE;
    returnObj["content"] = mRoleManager.TransformationAllRoleToJSON(role);

    this->Send(role->getWebSocket(),
               JsonToString(returnObj));

    // 给其它在线玩家发送当前玩家
    QJsonArray rolearray;
    QJsonObject roleObj;
    roleObj["type"] = role->getRoleType();
    roleObj["state"] = role->getState();
    roleObj["id"] = role->getID();
    roleObj["grade"] = role->getGrade();
    roleObj["name"] = role->getName();
    roleObj["posX"] = role->getPosition().x();
    roleObj["posY"] = role->getPosition().y();
    roleObj["angle"] = role->getAngle();
    roleObj["blood"] = role->getBlood();
    roleObj["defense"] = role->getDefense();
    roleObj["experience"] = role->getExperience();
    roleObj["shape"] = role->getShape();

    QJsonObject viewPortObj;
    viewPortObj["x"] = role->getMapViewRect().x();
    viewPortObj["y"] = role->getMapViewRect().y();
    viewPortObj["x1"] = role->getMapViewRect().bottomRight().x();
    viewPortObj["y1"] = role->getMapViewRect().bottomRight().y();

    roleObj["viewrect"] = viewPortObj;

    rolearray.push_back(roleObj);

    QJsonObject returnObj2;
    returnObj2["msgtype"] = IDD_NETWORK_ADDROLE;
    returnObj2["content"] = rolearray;

    QVector<BaseRole*> ptmpRoles = mRoleManager.getSameMapOtherRoles(role);
    for(int i=0;i<ptmpRoles.size();i++)
    {
        this->Send(ptmpRoles[i]->getWebSocket(),JsonToString(returnObj2));
    }
}

/**
 * @brief MapManager::update 更新
 */
void MapManager::update(void)
{
    if(!this->isListening())
        return;

    // 更新角色列表
    mRoleManager.update();

    // 更新地图中怪物列表
    QHash<int,BaseMap*>::iterator itermap = mBaseMapList.begin();
    for(;itermap != mBaseMapList.end();++itermap)
    {
        QList<BaseRole*> rolelist = itermap.value()->getTypeRoles(ROLETYPE_MONSTER);
        QList<BaseRole*>::iterator iterrole = rolelist.begin();
        for(;iterrole != rolelist.end();++iterrole)
        {
            (*iterrole)->update();
        }
    }
}

/**
 * @brief MapManager::updateRoleGameInfo 更新指定角色的游戏信息
 * @param role
 */
void MapManager::updateRoleGameInfo(BaseRole *role)
{
    if(role == NULL) return;

    QJsonObject contentObj;
    contentObj["roleid"] = role->getID();
    contentObj["blood"] = role->getBlood();
    contentObj["defense"] = role->getDefense();
    contentObj["experience"] = role->getExperience();
    contentObj["grade"] = role->getGrade();
    contentObj["usingbullet"] = role->getUsingBullet();

    QJsonArray bulletArr;
    QMap<int,int> bulletquantitylist = role->getBulletQuantity();
    QMap<int,int>::iterator iterbullet = bulletquantitylist.begin();
    for(;iterbullet != bulletquantitylist.end();++iterbullet)
    {
        QJsonObject bulletObj;
        bulletObj["id"] = iterbullet.key();
        bulletObj["quantity"] = iterbullet.value();

        bulletArr.push_back(bulletObj);
    }

    contentObj["bulletquantity"] = bulletArr;

    // 更新角色的血量
    QJsonObject mesObj;
    mesObj["msgtype"] = IDD_NETWORK_UPDATEROLEINFO;
    mesObj["content"] = contentObj;

    QVector<BaseRole*> ptmpRoles = mRoleManager.getSameMapAllRoles(role);
    for(int i=0;i<ptmpRoles.size();i++)
    {
        this->Send(ptmpRoles[i]->getWebSocket(),JsonToString(mesObj));
    }
}
